package com.vinjogames.util;

import android.graphics.PointF;

import com.vinjogames.entities.AttackObject;
import com.vinjogames.entities.Base;
import com.vinjogames.entities.Player;
import com.vinjogames.entities.Projectile;
import com.vinjogames.entities.Resource;
import com.vinjogames.entities.Turret;
import com.vinjogames.entities.Unit;


//TODO: Handle bases and resources differently since they should always be a constant count.
//Resources and bases are a static count for each map and only need to be held in memory somewhere.
public class MemoryManager {
	
	private static int i = 0;
	private static MemoryManager mgr;
	
	private Unit[] unitList;
	private boolean[] activeUnitList;
	
	private Turret[] turretList;
	private boolean[] activeTurretList;
	
	private Resource[] resourceList;
	private boolean[] activeResourceList;
	
	private Base[] baseList;
	private boolean[] activeBaseList;
	
	private Projectile[] projectileList;
	private boolean[] activeProjectileList;
	
	public MemoryManager(int maxUnits, int maxTurrets, int maxResources, int maxBases) {
		initializeManager(maxUnits, maxTurrets, maxResources, maxBases);
		mgr = this;
	}
	
	public void initializeManager(int maxUnits, int maxTurrets, int maxResources, int maxBases) {
		unitList = new Unit[maxUnits];
		activeUnitList = new boolean[maxUnits];
		for(i = 0; i < maxUnits; ++i)
			activeUnitList[i] = false;
		
		turretList = new Turret[maxTurrets];
		activeTurretList = new boolean[maxTurrets];
		for(i = 0; i < maxTurrets; ++i)
			activeTurretList[i] = false;
		
		resourceList = new Resource[maxResources];
		activeResourceList = new boolean[maxResources];
		for(i = 0; i < maxResources; ++i)
			activeResourceList[i] = false;
		
		baseList = new Base[maxBases];
		activeBaseList = new boolean[maxBases];
		for(i = 0; i < maxBases; ++i)
			activeBaseList[i] = false;
		
		projectileList = new Projectile[GameConVars.MAX_PROJECTILES];
		activeProjectileList = new boolean[GameConVars.MAX_PROJECTILES];
		for(i = 0; i < GameConVars.MAX_PROJECTILES; ++i)
			activeProjectileList[i] = false;
	}
	
	public static MemoryManager getInstance() { 
		if(mgr !=  null) return mgr;
		else return mgr = new MemoryManager(GameConVars.DEFAULT_PLAYERS * GameConVars.MAX_UNIT_COUNT_PER_PLAYER, 
				GameConVars.DEFAULT_MAX_TURRETS, GameConVars.DEFAULT_MAX_RESOURCES, GameConVars.DEFAULT_PLAYERS);
	}
	public Base getNewBase(float x, float y, Player p) {
		for(i = 0; i < baseList.length; ++i) {
			if(!activeBaseList[i]) {
				activeBaseList[i] = true;
				if(baseList[i] != null) {
					baseList[i].setX(x);
					baseList[i].setY(y);
					baseList[i].setPlayer(p);
					baseList[i].activateObject();
					return baseList[i];
				}
				else return baseList[i] = new Base(x, y, p);
			}
		}
		return null;
	}
	public Unit getNewUnit(int type, Player p) {
		for(i = 0; i < unitList.length; ++i) {
			if(!activeUnitList[i]) {
				activeUnitList[i] = true;
				//We found one that isn't active, lets initialize it and send it off.
				if(unitList[i] != null) {
					unitList[i].turnIntoType(type, p);
					unitList[i].activateObject();
					return unitList[i];
				}					
				else return unitList[i] = new Unit(type, p);
			}
		}
		return null;
	}	
	public Resource getNewResource(float x, float y) {
		for(i = 0; i < resourceList.length; ++i) {
			if(!activeResourceList[i]) {
				activeResourceList[i] = true;
				if(resourceList[i] != null) {
					resourceList[i].setX(x);
					resourceList[i].setY(y);
					//Reset the damn resource.
					return resourceList[i];
				}else return new Resource(x,y);
			}
		}
		return null;
	}
	public Turret getNewTurret(int type, Player p, float x, float y) {
		for(i = 0; i < turretList.length; ++i) {
			if(!activeTurretList[i]) {
				activeTurretList[i] = true;
				if(turretList[i] != null) {
					turretList[i].turnIntoType(type, p, x, y);
					turretList[i].activateObject();
					return turretList[i];
				}
				else return turretList[i] = new Turret(type, p, x, y);
			}
		}
		return null;
	}	
	public Projectile getNewProjectile(AttackObject obj, PointF loc, VectorF dir, int cost, float dmg) {
		for(i = 0; i < projectileList.length; ++i) {
			if(!activeProjectileList[i]) {
				activeProjectileList[i] = true;
				if(projectileList[i] != null) {
					projectileList[i].initializeTo(obj, loc, dir, cost, dmg);
					return projectileList[i];
				}
				else return projectileList[i] = new Projectile(obj, loc, dir, cost, dmg);
			}
		}
		return null;
	}
	
	//Functions to release objects from active status so that they can be re-initialized.
	public boolean releaseUnit(Unit u) {
		for(i = 0; i < unitList.length; ++i) {
			if(unitList[i] == u && activeUnitList[i]) {
				activeUnitList[i] = false;
				unitList[i].clearInfo();
				return true;
			}
		}
		return false;
	}	
	public boolean releaseTurret(Turret t) {
		for(i = 0; i < turretList.length; ++i) {
			if(turretList[i] == t && activeTurretList[i]) {
				activeTurretList[i] = false;
				turretList[i].clearInfo();
				return true;
			}
		}
		return false;		
	}	
	public boolean releaseResource(Resource r) {
		for(i = 0; i < resourceList.length; ++i) {
			if(resourceList[i] == r && activeResourceList[i]) {
				activeResourceList[i] = false;
				resourceList[i].clearInfo();
				return true;
			}
		}
		return false;
	}	
	public boolean releaseProjectile(Projectile p) {
		for(i = 0; i < projectileList.length; ++i) {
			if(projectileList[i] == p && activeProjectileList[i]) {
				activeProjectileList[i] = false;
				projectileList[i].clearInfo();
				return true;
			}
		}
		return false;
	}
	
	public void clearMemory() {
		mgr =  null;
		for(i = 0; i < activeProjectileList.length; ++i) activeProjectileList[i] = false;
		for(i = 0; i < activeBaseList.length; ++i) activeBaseList[i] = false;
		for(i = 0; i < activeResourceList.length; ++i) activeResourceList[i] = false;
		for(i = 0; i < activeTurretList.length; ++i) activeTurretList[i] = false;
		for(i = 0; i < activeUnitList.length; ++i) activeUnitList[i] = false;
	}
}
